React Portal์ ์ฌ์ฉํ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ์ ์ด์ ๋ํ ์ฌ์ธต ๋ถ์์ ๋๋ค. ์ด๋ฒคํธ๋ฅผ ์ ํ์ ์ผ๋ก ์ ํํ๊ณ ์์ธก ๊ฐ๋ฅํ UI๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.
React Portal ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ์ ์ด: ์ ํ์ ์ด๋ฒคํธ ์ ํ
React Portal์ ํ์ค React ์ปดํฌ๋ํธ ๊ณ์ธต ๊ตฌ์กฐ ์ธ๋ถ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ ๋ชจ๋ฌ, ํดํ, ์ค๋ฒ๋ ์ด์ ๊ฐ์ด ๋ ผ๋ฆฌ์ ๋ถ๋ชจ์ ๋ ๋ฆฝ์ ์ผ๋ก ์์๋ฅผ ์๊ฐ์ ์ผ๋ก ๋ฐฐ์นํด์ผ ํ๋ ์๋๋ฆฌ์ค์ ๋งค์ฐ ์ ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ DOM ํธ๋ฆฌ๋ก๋ถํฐ์ ์ด๋ฌํ ๋ถ๋ฆฌ๋ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ๋ณต์ก์ฑ์ ์ผ๊ธฐํ ์ ์์ผ๋ฉฐ, ์ฃผ์ ๊น๊ฒ ๊ด๋ฆฌํ์ง ์์ผ๋ฉด ์๊ธฐ์น ์์ ๋์์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ์ด ๊ธฐ์ฌ์์๋ React Portal์ ์ฌ์ฉํ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ๋ณต์ก์ฑ์ ์ดํด๋ณด๊ณ ์ํ๋ ์ปดํฌ๋ํธ ์ํธ ์์ฉ์ ๋ฌ์ฑํ๊ธฐ ์ํด ์ด๋ฒคํธ๋ฅผ ์ ํ์ ์ผ๋ก ์ ํํ๋ ์ ๋ต์ ์ ๊ณตํฉ๋๋ค.
DOM์์ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ์ดํด
React Portal์ ๋ค์ด๊ฐ๊ธฐ ์ ์ DOM(Document Object Model)์์ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ๊ธฐ๋ณธ ๊ฐ๋
์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. HTML ์์์์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ๋จผ์ ํด๋น ์์(๋์)์ ์ฐ๊ฒฐ๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด๋ฒคํธ๋ DOM ํธ๋ฆฌ๋ฅผ ๋ฐ๋ผ "๋ฒ๋ธ"๋์ด ๋ฌธ์์ ๋ฃจํธ(window)๊น์ง ๊ฐ ๋ถ๋ชจ ์์์์ ๋์ผํ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค. ์ด ๋์์ ํตํด ๊ฐ ์์ ์์์ ๊ฐ๋ณ ๋ฆฌ์ค๋๋ฅผ ์ฐ๊ฒฐํ๋ ๋์ ๋จ์ผ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ถ๋ชจ ์์์ ์ฐ๊ฒฐํ ์ ์์ผ๋ฏ๋ก ์ด๋ฒคํธ๋ฅผ ๋ณด๋ค ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ๋ค์ HTML ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
<div id="parent">
<button id="child">Click Me</button>
</div>
#child ๋ฒํผ๊ณผ #parent div ๋ชจ๋์ click ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ฐ๊ฒฐํ๋ฉด ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋จผ์ ๋ฒํผ์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ํธ๋ฆฌ๊ฑฐ๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด๋ฒคํธ๋ ๋ถ๋ชจ div๋ก ๋ฒ๋ธ๋ง๋์ด ํด๋น click ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ํธ๋ฆฌ๊ฑฐํฉ๋๋ค.
React Portal ๋ฐ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ๋ฌธ์ ์
React Portal์ ์์์ DOM์ ๋ค๋ฅธ ์์น์ ๋ ๋๋งํ์ฌ ํจ๊ณผ์ ์ผ๋ก React ์ปดํฌ๋ํธ ๊ณ์ธต ๊ตฌ์กฐ์ ์ฐ๊ฒฐ์ ์ปดํฌ๋ํธ ํธ๋ฆฌ์ ์๋ ๋ถ๋ชจ์ ๋ถ๋ฆฌํฉ๋๋ค. React ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ ๊ทธ๋๋ก ์ ์ง๋์ง๋ง DOM ๊ตฌ์กฐ๋ ๋ณ๊ฒฝ๋ฉ๋๋ค. ์ด๋ฌํ ๋ณ๊ฒฝ์ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ๋ฌธ์ ๋ฅผ ์ผ์ผํฌ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ํฌํธ ๋ด์์ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ ์ฌ์ ํ DOM ํธ๋ฆฌ๋ฅผ ๋ฐ๋ผ ๋ฒ๋ธ๋ง๋์ด React ์ ํ๋ฆฌ์ผ์ด์ ์ธ๋ถ์ ์์ ๋๋ ํด๋น ์์๊ฐ ํฌํธ์ ์ฝํ ์ธ ๊ฐ ๋ ๋๋ง๋๋ *DOM ํธ๋ฆฌ*์ ์์ ์์์ธ ๊ฒฝ์ฐ ์ ํ๋ฆฌ์ผ์ด์ ๋ด์ ์๊ธฐ์น ์์ ๋ถ๋ชจ ์์์์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ํธ๋ฆฌ๊ฑฐํ ์ ์์ต๋๋ค. ์ด ๋ฒ๋ธ๋ง์ React ์ปดํฌ๋ํธ ํธ๋ฆฌ๊ฐ *์๋* DOM์์ ๋ฐ์ํฉ๋๋ค.
React Portal์ ์ฌ์ฉํ์ฌ ๋ ๋๋ง๋ ๋ชจ๋ฌ ์ปดํฌ๋ํธ๊ฐ ์๋ ์๋๋ฆฌ์ค๋ฅผ ์๊ฐํด ๋ณด์ญ์์ค. ๋ชจ๋ฌ์๋ ๋ฒํผ์ด ํฌํจ๋์ด ์์ต๋๋ค. ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ด๋ฒคํธ๊ฐ body ์์(ํฌํธ์ ํตํด ๋ชจ๋ฌ์ด ๋ ๋๋ง๋๋ ์์น)๋ก ๋ฒ๋ธ๋ง๋ ๋ค์ DOM ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ชจ๋ฌ ์ธ๋ถ์ ๋ค๋ฅธ ์์๋ก ๋ฒ๋ธ๋ง๋ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ค๋ฅธ ์์์ ํด๋ฆญ ํธ๋ค๋ฌ๊ฐ ์๋ ๊ฒฝ์ฐ ์๊ธฐ์น ์๊ฒ ํธ๋ฆฌ๊ฑฐ๋์ด ์๋ํ์ง ์์ ๋ถ์์ฉ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
React Portal๋ก ์ด๋ฒคํธ ์ ํ ์ ์ด
React Portal๋ก ์ธํด ๋ฐ์ํ๋ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ์ด๋ฒคํธ ์ ํ๋ฅผ ์ ํ์ ์ผ๋ก ์ ์ดํด์ผ ํฉ๋๋ค. ์ทจํ ์ ์๋ ๋ช ๊ฐ์ง ์ ๊ทผ ๋ฐฉ์์ด ์์ต๋๋ค.
1. stopPropagation() ์ฌ์ฉ
๊ฐ์ฅ ๊ฐ๋จํ ์ ๊ทผ ๋ฐฉ์์ ์ด๋ฒคํธ ๊ฐ์ฒด์์ stopPropagation() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค. ์ด ๋ฉ์๋๋ ์ด๋ฒคํธ๊ฐ DOM ํธ๋ฆฌ์์ ๋ ์ด์ ๋ฒ๋ธ๋ง๋์ง ์๋๋ก ํฉ๋๋ค. ํฌํธ ๋ด์ ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ด์์ stopPropagation()์ ํธ์ถํ ์ ์์ต๋๋ค.
์์ :
import React from 'react';
import ReactDOM from 'react-dom';
const modalRoot = document.getElementById('modal-root'); // HTML์ modal-root ์์๊ฐ ์๋์ง ํ์ธํฉ๋๋ค.
function Modal(props) {
return ReactDOM.createPortal(
<div className="modal" onClick={(e) => e.stopPropagation()}>
<div className="modal-content">
{props.children}
</div>
</div>,
modalRoot
);
}
function App() {
const [showModal, setShowModal] = React.useState(false);
return (
<div>
<button onClick={() => setShowModal(true)}>Open Modal</button>
{showModal && (
<Modal>
<button onClick={() => alert('Button inside modal clicked!')}>Click Me Inside Modal</button>
</Modal>
)}
<div onClick={() => alert('Click outside modal!')}>
Click here outside the modal
</div>
</div>
);
}
export default App;
์ด ์์ ์์ .modal div์ ์ฐ๊ฒฐ๋ onClick ํธ๋ค๋ฌ๋ e.stopPropagation()์ ํธ์ถํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ฌ ๋ด์ ํด๋ฆญ์ด ๋ชจ๋ฌ ์ธ๋ถ์ <div>์์ onClick ํธ๋ค๋ฌ๋ฅผ ํธ๋ฆฌ๊ฑฐํ์ง ๋ชปํฉ๋๋ค.
๊ณ ๋ ค ์ฌํญ:
stopPropagation()์ ์ด๋ฒคํธ๊ฐ React ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ๊ด๋ จ์ด ์๋์ง ์ฌ๋ถ์ ๊ด๊ณ์์ด DOM ํธ๋ฆฌ์์ ๋ ๋์ ์์น์ ์๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋๊ฐ ๋ ์ด์ ํธ๋ฆฌ๊ฑฐ๋์ง ์๋๋ก ํฉ๋๋ค.- ์ด ๋ฉ์๋๋ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ๋์์ ์์กดํ ์ ์๋ ๋ค๋ฅธ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ฐฉํดํ ์ ์์ผ๋ฏ๋ก ์ ์คํ๊ฒ ์ฌ์ฉํ์ญ์์ค.
2. ๋์์ ๋ฐ๋ฅธ ์กฐ๊ฑด๋ถ ์ด๋ฒคํธ ์ฒ๋ฆฌ
๋ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ์ด๋ฒคํธ ๋์์ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฒคํธ๋ฅผ ์กฐ๊ฑด๋ถ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ ๋๋ค. ์ด๋ฒคํธ ๋์์ด ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ก์ง์ ์คํํ๊ธฐ ์ ์ ํฌํธ ๋ด์ ์๋์ง ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํฌํธ ์ธ๋ถ์์ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ์ ํ์ ์ผ๋ก ๋ฌด์ํ ์ ์์ต๋๋ค.
์์ :
import React from 'react';
import ReactDOM from 'react-dom';
const modalRoot = document.getElementById('modal-root');
function Modal(props) {
return ReactDOM.createPortal(
<div className="modal">
<div className="modal-content">
{props.children}
</div>
</div>,
modalRoot
);
}
function App() {
const [showModal, setShowModal] = React.useState(false);
const handleClickOutsideModal = (event) => {
if (showModal && !modalRoot.contains(event.target)) {
alert('Clicked outside the modal!');
setShowModal(false);
}
};
React.useEffect(() => {
document.addEventListener('mousedown', handleClickOutsideModal);
return () => {
document.removeEventListener('mousedown', handleClickOutsideModal);
};
}, [showModal]);
return (
<div>
<button onClick={() => setShowModal(true)}>Open Modal</button>
{showModal && (
<Modal>
<button onClick={() => alert('Button inside modal clicked!')}>Click Me Inside Modal</button>
</Modal>
)}
</div>
);
}
export default App;
์ด ์์ ์์ handleClickOutsideModal ํจ์๋ ์ด๋ฒคํธ ๋์(event.target)์ด modalRoot ์์ ๋ด์ ํฌํจ๋์ด ์๋์ง ํ์ธํฉ๋๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ํด๋ฆญ์ด ๋ชจ๋ฌ ์ธ๋ถ์์ ๋ฐ์ํ์์ ์๋ฏธํ๋ฉฐ ๋ชจ๋ฌ์ด ๋ซํ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ชจ๋ฌ ๋ด๋ถ์ ์ค์๋ก ์ธํ ํด๋ฆญ์ด "์ธ๋ถ ํด๋ฆญ" ๋ก์ง์ ํธ๋ฆฌ๊ฑฐํ์ง ์๋๋ก ํฉ๋๋ค.
๊ณ ๋ ค ์ฌํญ:
- ์ด ์ ๊ทผ ๋ฐฉ์์์๋ ํฌํธ์ด ๋ ๋๋ง๋๋ ๋ฃจํธ ์์(์:
modalRoot)์ ๋ํ ์ฐธ์กฐ๊ฐ ์์ด์ผ ํฉ๋๋ค. - ํฌํธ ๋ด์ ์ค์ฒฉ๋ ์์์ ๊ฒฝ์ฐ ์ด๋ฒคํธ ๋์์ ์๋์ผ๋ก ํ์ธํ๋ ๊ฒ์ด ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
- ์ฌ์ฉ์๊ฐ ๋ชจ๋ฌ ๋๋ ์ ์ฌํ ์ปดํฌ๋ํธ ์ธ๋ถ๋ฅผ ํด๋ฆญํ ๋ ํน์ ์์ ์ ํธ๋ฆฌ๊ฑฐํ๋ ค๋ ์๋๋ฆฌ์ค๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
3. ์บก์ฒ ๋จ๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ฌ์ฉ
์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ๊ธฐ๋ณธ ๋์์ด์ง๋ง ์ด๋ฒคํธ๋ ๋ฒ๋ธ๋ง ๋จ๊ณ ์ ์ "์บก์ฒ" ๋จ๊ณ๋ฅผ ๊ฑฐ์นฉ๋๋ค. ์บก์ฒ ๋จ๊ณ ๋์ ์ด๋ฒคํธ๋ ์ฐฝ์์ ๋์ ์์๋ก DOM ํธ๋ฆฌ๋ฅผ ๋ฐ๋ผ ์ด๋ํฉ๋๋ค. ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ถ๊ฐํ ๋ useCapture ์ต์
์ true๋ก ์ค์ ํ์ฌ ์บก์ฒ ๋จ๊ณ์์ ์ด๋ฒคํธ๋ฅผ ์์ ํ๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค.
์บก์ฒ ๋จ๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ฌธ์(๋๋ ๋ค๋ฅธ ์ ์ ํ ์์ ์์)์ ์ฐ๊ฒฐํ๋ฉด ์ด๋ฒคํธ๊ฐ ํฌํธ์ ๋๋ฌํ๊ธฐ ์ ์ ์ด๋ฒคํธ๋ฅผ ๊ฐ๋ก์ฑ์ ๋ฒ๋ธ๋ง๋๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค. ์ด๋ ์ด๋ฒคํธ๊ฐ ๋ค๋ฅธ ์์์ ๋๋ฌํ๊ธฐ ์ ์ ์ด๋ฒคํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ผ๋ถ ์์ ์ ์ํํด์ผ ํ๋ ๊ฒฝ์ฐ์ ์ ์ฉํ ์ ์์ต๋๋ค.
์์ :
import React from 'react';
import ReactDOM from 'react-dom';
const modalRoot = document.getElementById('modal-root');
function Modal(props) {
return ReactDOM.createPortal(
<div className="modal">
<div className="modal-content">
{props.children}
</div>
</div>,
modalRoot
);
}
function App() {
const [showModal, setShowModal] = React.useState(false);
const handleCapture = (event) => {
// ์ด๋ฒคํธ๊ฐ modal-root ๋ด๋ถ์์ ๋ฐ์ํ ๊ฒฝ์ฐ ์๋ฌด ์์
๋ ์ํํ์ง ์์ต๋๋ค.
if (modalRoot.contains(event.target)) {
return;
}
// ์ด๋ฒคํธ๊ฐ ๋ชจ๋ฌ ์ธ๋ถ์์ ๋ฐ์ํ ๊ฒฝ์ฐ ์ด๋ฒคํธ๊ฐ ๋ฒ๋ธ๋ง๋์ง ์๋๋ก ํฉ๋๋ค.
console.log('Event captured outside the modal!', event.target);
event.stopPropagation();
setShowModal(false);
};
React.useEffect(() => {
document.addEventListener('click', handleCapture, true); // ์บก์ฒ ๋จ๊ณ!
return () => {
document.removeEventListener('click', handleCapture, true);
};
}, [showModal]);
return (
<div>
<button onClick={() => setShowModal(true)}>Open Modal</button>
{showModal && (
<Modal>
<button onClick={() => alert('Button inside modal clicked!')}>Click Me Inside Modal</button>
</Modal>
)}
</div>
);
}
export default App;
์ด ์์ ์์ handleCapture ํจ์๋ useCapture: true ์ต์
์ ์ฌ์ฉํ์ฌ ๋ฌธ์์ ์ฐ๊ฒฐ๋ฉ๋๋ค. ์ฆ, handleCapture๋ ํ์ด์ง์ ๋ค๋ฅธ ํด๋ฆญ ํธ๋ค๋ฌ *์ ์* ํธ์ถ๋ฉ๋๋ค. ํจ์๋ ์ด๋ฒคํธ ๋์์ด modalRoot ๋ด์ ์๋์ง ํ์ธํฉ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ฒคํธ๋ ๊ณ์ ๋ฒ๋ธ๋ง๋ ์ ์์ต๋๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ event.stopPropagation()์ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ๊ฐ ๋ฒ๋ธ๋ง๋์ง ์๋๋ก ํ๊ณ ๋ชจ๋ฌ์ด ๋ซํ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ฌ ์ธ๋ถ์ ํด๋ฆญ์ด ์๋ก ์ ํ๋๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๊ณ ๋ ค ์ฌํญ:
- ์บก์ฒ ๋จ๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ ๋ฒ๋ธ๋ง ๋จ๊ณ ๋ฆฌ์ค๋ *์ ์* ์คํ๋๋ฏ๋ก ์ฃผ์ํด์ ์ฌ์ฉํ์ง ์์ผ๋ฉด ํ์ด์ง์ ๋ค๋ฅธ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ฐฉํดํ ์ ์์ต๋๋ค.
- ์ด ์ ๊ทผ ๋ฐฉ์์
stopPropagation()๋๋ ์กฐ๊ฑด๋ถ ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ณด๋ค ์ดํดํ๊ณ ๋๋ฒ๊ทธํ๊ธฐ๊ฐ ๋ ๋ณต์กํ ์ ์์ต๋๋ค. - ์ด๋ฒคํธ ํ๋ฆ ์ด๊ธฐ์ ์ด๋ฒคํธ๋ฅผ ๊ฐ๋ก์ฑ์ผ ํ๋ ํน์ ์๋๋ฆฌ์ค์์ ์ ์ฉํ ์ ์์ต๋๋ค.
4. React์ ํฉ์ฑ ์ด๋ฒคํธ ๋ฐ Portal์ DOM ์์น
React์ ํฉ์ฑ ์ด๋ฒคํธ ์์คํ ์ ๊ธฐ์ตํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. React๋ ๋ค์ดํฐ๋ธ DOM ์ด๋ฒคํธ๋ฅผ ํฌ๋ก์ค ๋ธ๋ผ์ฐ์ ๋ํผ์ธ ํฉ์ฑ ์ด๋ฒคํธ๋ก ๋ํํฉ๋๋ค. ์ด ์ถ์ํ๋ React์์ ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ฅผ ๋จ์ํํ์ง๋ง ๊ธฐ๋ณธ DOM ์ด๋ฒคํธ๋ ์ฌ์ ํ ๋ฐ์ํ๊ณ ์์์ ์๋ฏธํฉ๋๋ค. React ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ๋ฃจํธ ์์์ ์ฐ๊ฒฐ๋ ๋ค์ ์ ์ ํ ์ปดํฌ๋ํธ์ ์์๋ฉ๋๋ค. ๊ทธ๋ฌ๋ Portal์ DOM ๋ ๋๋ง ์์น๋ฅผ ๋ณ๊ฒฝํ์ง๋ง React ์ปดํฌ๋ํธ ๊ตฌ์กฐ๋ ๋์ผํ๊ฒ ์ ์ง๋ฉ๋๋ค.
๋ฐ๋ผ์ ํฌํธ์ ์ฝํ
์ธ ๊ฐ DOM์ ๋ค๋ฅธ ๋ถ๋ถ์ ๋ ๋๋ง๋๋๋ผ๋ React์ ์ด๋ฒคํธ ์์คํ
์ ์ฌ์ ํ ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋ํฉ๋๋ค. ์ฆ, React์์ ๊ด๋ฆฌํ๋ DOM ์์ญ *์ธ๋ถ*์์ ๋ฒ๋ธ๋ง์ ํน๋ณํ ๋ฐฉ์งํ ํ์๊ฐ ์๋ ํ DOM ์ด๋ฒคํธ ํ๋ฆ์ ์ง์ ์กฐ์ํ์ง ์๊ณ ๋ ํฌํธ ๋ด์์ React์ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ(์: onClick)์ ๊ณ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
React Portal์ ์ฌ์ฉํ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ๋ํ ๋ชจ๋ฒ ์ฌ๋ก
React Portal ๋ฐ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ์ฌ์ฉํ ๋ ๋ช ์ฌํด์ผ ํ ๋ช ๊ฐ์ง ๋ชจ๋ฒ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- DOM ๊ตฌ์กฐ ์ดํด: ํฌํธ์ด ๋ ๋๋ง๋๋ DOM ๊ตฌ์กฐ๋ฅผ ์ฃผ์ ๊น๊ฒ ๋ถ์ํ์ฌ ์ด๋ฒคํธ๊ฐ ํธ๋ฆฌ๋ฅผ ๋ฐ๋ผ ๋ฒ๋ธ๋ง๋๋ ๋ฐฉ์์ ์ดํดํฉ๋๋ค.
stopPropagation()์ ๋๋ฌผ๊ฒ ์ฌ์ฉ:stopPropagation()์ ์๋ํ์ง ์์ ๋ถ์์ฉ์ด ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก ์ ๋์ ์ผ๋ก ํ์ํ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํ์ญ์์ค.- ์กฐ๊ฑด๋ถ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๊ณ ๋ ค: ์ด๋ฒคํธ ๋์์ ๊ธฐ๋ฐ์ผ๋ก ์กฐ๊ฑด๋ถ ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํฌํธ ๋ด์์ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ์ ํ์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
- ์บก์ฒ ๋จ๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ํ์ฉ: ํน์ ์๋๋ฆฌ์ค์์๋ ์บก์ฒ ๋จ๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ ํ๋ฆ ์ด๊ธฐ์ ์ด๋ฒคํธ๋ฅผ ๊ฐ๋ก์ฑ๋ ๊ฒ์ ๊ณ ๋ คํ์ญ์์ค.
- ์ฒ ์ ํ ํ ์คํธ: ์ปดํฌ๋ํธ๋ฅผ ์ฒ ์ ํ ํ ์คํธํ์ฌ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ด ์์๋๋ก ์๋ํ๊ณ ์๋ํ์ง ์์ ๋ถ์์ฉ์ด ์๋์ง ํ์ธํฉ๋๋ค.
- ์ฝ๋ ๋ฌธ์ํ: React Portal์ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํ๊ธฐ ์ํด ์ฝ๋๋ฅผ ๋ช ํํ๊ฒ ๋ฌธ์ํํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ค๋ฅธ ๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ฅผ ์ดํดํ๊ณ ์ ์ง ๊ด๋ฆฌํ๊ธฐ๊ฐ ๋ ์ฌ์์ง๋๋ค.
- ์ ๊ทผ์ฑ ๊ณ ๋ ค: ์ด๋ฒคํธ ์ ํ๋ฅผ ๊ด๋ฆฌํ ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๊ทผ์ฑ์ ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ก ํ์ญ์์ค. ์๋ฅผ ๋ค์ด ํค๋ณด๋ ์ด๋ฒคํธ๊ฐ ์ค์๋ก ์ฐจ๋จ๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
- ์ฑ๋ฅ: ํนํ
document๋๋window๊ฐ์ฒด์ ๊ณผ๋ํ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ถ๊ฐํ์ง ๋ง์ญ์์ค. ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค. ์ ์ ํ ๊ฒฝ์ฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋๋ฐ์ด์คํ๊ฑฐ๋ ์ค๋กํ๋งํ์ญ์์ค.
์ค์ ์์
React Portal์ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ์ ์ดํ๋ ๊ฒ์ด ํ์์ ์ธ ๋ช ๊ฐ์ง ์ค์ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
- ๋ชจ๋ฌ: ์์ ์์ ์์ ์ ์ฆ๋ ๋ฐ์ ๊ฐ์ด ๋ชจ๋ฌ์ React Portal์ ๊ณ ์ ์ ์ธ ์ฌ์ฉ ์ฌ๋ก์ ๋๋ค. ๋ชจ๋ฌ ๋ด์ ํด๋ฆญ์ด ๋ชจ๋ฌ ์ธ๋ถ์์ ์์ ์ ํธ๋ฆฌ๊ฑฐํ๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๊ฒ์ ์ข์ ์ฌ์ฉ์ ๊ฒฝํ์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- ํดํ: ํดํ์ ์ข ์ข ํฌํธ์ ์ฌ์ฉํ์ฌ ๋์ ์์์ ์๋์ ์ผ๋ก ๋ฐฐ์น๋ฉ๋๋ค. ํดํ์ ํด๋ฆญํ๋ฉด ๋ถ๋ชจ ์์๊ฐ ๋ซํ์ง ์๋๋ก ๋ฐฉ์งํ ์ ์์ต๋๋ค.
- ์ปจํ ์คํธ ๋ฉ๋ด: ์ปจํ ์คํธ ๋ฉ๋ด๋ ์ผ๋ฐ์ ์ผ๋ก ํฌํธ์ ์ฌ์ฉํ์ฌ ๋ง์ฐ์ค ์ปค์ ๊ทผ์ฒ์ ๋ฐฐ์น๋ฉ๋๋ค. ์ปจํ ์คํธ ๋ฉ๋ด๋ฅผ ํด๋ฆญํ๋ฉด ๊ธฐ๋ณธ ํ์ด์ง์์ ์์ ์ด ํธ๋ฆฌ๊ฑฐ๋์ง ์๋๋ก ๋ฐฉ์งํ ์ ์์ต๋๋ค.
- ๋๋กญ๋ค์ด ๋ฉ๋ด: ์ปจํ ์คํธ ๋ฉ๋ด์ ์ ์ฌํ๊ฒ ๋๋กญ๋ค์ด ๋ฉ๋ด๋ ์ข ์ข ํฌํธ์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ฒคํธ ์ ํ๋ฅผ ์ ์ดํ๋ ๊ฒ์ ๋ฉ๋ด ๋ด๋ถ์ ์ค์๋ก ์ธํ ํด๋ฆญ์ผ๋ก ์ธํด ๋ฉ๋ด๊ฐ ์กฐ๊ธฐ์ ๋ซํ๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๋ฐ ํ์ํฉ๋๋ค.
- ์๋ฆผ: ์๋ฆผ์ ํฌํธ์ ์ฌ์ฉํ์ฌ ํ๋ฉด์ ํน์ ์์ญ(์: ์ค๋ฅธ์ชฝ ์๋จ)์ ๋ฐฐ์นํ ์ ์์ต๋๋ค. ์๋ฆผ์ ํด๋ฆญํ๋ฉด ๊ธฐ๋ณธ ํ์ด์ง์์ ์์ ์ด ํธ๋ฆฌ๊ฑฐ๋์ง ์๋๋ก ๋ฐฉ์งํ๋ฉด ์ ์ฉ์ฑ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
๊ฒฐ๋ก
React Portal์ ํ์ค React ์ปดํฌ๋ํธ ๊ณ์ธต ๊ตฌ์กฐ ์ธ๋ถ์์ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ง๋ง ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ๋ณต์ก์ฑ์ ์ผ๊ธฐํฉ๋๋ค. DOM ์ด๋ฒคํธ ๋ชจ๋ธ์ ์ดํดํ๊ณ stopPropagation(), ์กฐ๊ฑด๋ถ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฐ ์บก์ฒ ๋จ๊ณ ์ด๋ฒคํธ ๋ฆฌ์ค๋์ ๊ฐ์ ๊ธฐ์ ์ ์ฌ์ฉํ๋ฉด ์ด๋ฒคํธ ์ ํ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ ์ดํ๊ณ ๋ณด๋ค ์์ธก ๊ฐ๋ฅํ๊ณ ์ ์ง ๊ด๋ฆฌ ๊ฐ๋ฅํ ์ฌ์ฉ์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌ์ถํ ์ ์์ต๋๋ค. React Portal ๋ฐ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ์ฌ์ฉํ ๋๋ DOM ๊ตฌ์กฐ, ์ ๊ทผ์ฑ ๋ฐ ์ฑ๋ฅ์ ์ ์คํ๊ฒ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ปดํฌ๋ํธ๋ฅผ ์ฒ ์ ํ ํ
์คํธํ๊ณ ์ฝ๋๋ฅผ ๋ฌธ์ํํ์ฌ ์ด๋ฒคํธ ์ฒ๋ฆฌ๊ฐ ์์๋๋ก ์๋ํ๋์ง ํ์ธํ์ญ์์ค.
React Portal์ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง ์ ์ด๋ฅผ ๋ง์คํฐํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ์ํํ๊ฒ ํตํฉ๋์ด ์ ๋ฐ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๊ณ ์ฝ๋ ๋ฒ ์ด์ค๋ฅผ ๋์ฑ ๊ฐ๋ ฅํ๊ฒ ๋ง๋๋ ์ ๊ตํ๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ๊ฐ๋ฐ ๋ฐฉ์์ด ๋ฐ์ ํจ์ ๋ฐ๋ผ ์ด๋ฒคํธ ์ฒ๋ฆฌ์ ๋์์ค๋ฅผ ๋ฐ๋ผ๊ฐ๋ ๊ฒ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ ์ธ๊ณ์ ์ผ๋ก ๋ฐ์์ฑ์ด ๋ฐ์ด๋๊ณ ์ ๊ทผ ๊ฐ๋ฅํ๋ฉฐ ์ ์ง ๊ด๋ฆฌ ๊ฐ๋ฅํ๋๋ก ๋ณด์ฅํฉ๋๋ค.